import { GameEvent } from "./GameEvent";
import { PlayerController } from "./PlayerController";
import { StarData } from "./StarData";
import { UpdateRegister } from "./UpdateRegister";

export class StarController implements GameCtrler{
    private starPrefab: cc.Prefab;
    private starGroupRoot: cc.Node;
    private starAliveTime: number;
    private createStarInterval: number;
    private createStarAreaLimit: cc.Vec4;
    private isGameStarted: boolean;
    private activeStars: Array<StarData>;
    private disableStars: Array<cc.Node>;
    private detectRadius: number;
    private player: PlayerController;

    private lastGetStarTime: number;
    private curTime: number;

    public constructor(starAliveTime:number, createStarInterval: number, createStarAreaLimit:cc.Vec4, detectRadius: number, player: PlayerController){
        this.starAliveTime = starAliveTime;
        this.createStarInterval = createStarInterval;
        this.createStarAreaLimit = createStarAreaLimit;
        this.starGroupRoot = cc.find('game/star_group_root');
        this.activeStars = new Array<StarData>;
        this.disableStars = new Array<cc.Node>;
        this.detectRadius = detectRadius;
        this.player = player;
        UpdateRegister.register(this.update.bind(this));
    }

    public prepareGame(): void {
    }

    public startGame(): void{
        if(this.starPrefab == null){
            cc.loader.loadRes('star', cc.Prefab, this.loadStarPrefab.bind(this));
        }
        else{
            this.isGameStarted = true;
        }

        this.lastGetStarTime = 0;
        this.curTime = 0;
    }

    public finishGame(): void{
        this.isGameStarted = false;
        this.recycleAllStar();
    }

    public restartGame(): void {
        this.startGame();
    }

    private update(dt: number): void {
        if(!this.isGameStarted){
            return;
        }

        //监测
        this.activeStars.forEach(element => {
            if(cc.Vec3.distance(element.starNode.position, this.player.getPos()) <= this.detectRadius){
                //移除
                element.starNode.active = false;
                let idx = this.activeStars.indexOf(element);
                this.activeStars.splice(idx, 1);
                this.disableStars.push(element.starNode);
                //得分
                GameEvent.OnPlayerGetScore(1);
            }
        })

        //生成
        this.curTime += dt;
        if(this.curTime - this.lastGetStarTime >= this.createStarInterval){
            this.lastGetStarTime = this.curTime;
            this.spawnStar();
        }

        //回收
        this.activeStars.forEach(element => {
            element.remainAliveTime -= dt;
            if(element.remainAliveTime <= 0){
                element.starNode.active = false;
                let idx = this.activeStars.indexOf(element);
                this.activeStars.splice(idx, 1);

                this.disableStars.push(element.starNode);
            }
        })
    }

    private spawnStar(): void{
        let randomPos = this.randomStarPos();
        let newStarData = this.getStar(randomPos);
        this.activeStars.push(newStarData);
    }

    private getStar(pos: cc.Vec3): StarData{
        let result: StarData = null;
        if(this.disableStars.length <= 0){
            result = this.createStar(pos);
        }
        else{
            let newStarNode = this.disableStars.pop();
            newStarNode.active = true;
            newStarNode.parent = this.starGroupRoot;
            newStarNode.position = pos;
            result = new StarData(this.starAliveTime, newStarNode);
        }

        return result;
    }

    private createStar(pos: cc.Vec3): StarData{
        let newStarNode = cc.instantiate(this.starPrefab);
        newStarNode.active = true;
        newStarNode.parent = this.starGroupRoot;
        newStarNode.position = pos;

        let result = new StarData(this.starAliveTime, newStarNode);

        return result;
    }

    private recycleAllStar(): void{
        this.activeStars.forEach(element => {
            element.starNode.active = false;
            this.disableStars.push(element.starNode);
        })
        this.activeStars.length = 0;
    }

    private randomStarPos(): cc.Vec3{
        let randomX = this.createStarAreaLimit.y * Math.random() * (Math.random() < 0.5 ? -1 : 1);
        let randomY = this.createStarAreaLimit.z * Math.random() * (Math.random() < 0.5 ? -1 : 1);
        return new cc.Vec3(randomX, randomY, 0);
    }

    private loadStarPrefab(error: Error, res: any): void{
        this.starPrefab = res;
        this.isGameStarted = true;
    }
}
